package cn.com.open.itembank.service.impl;

import cn.com.open.itembank.common.GlobalConst;
import cn.com.open.itembank.common.enums.*;
import cn.com.open.itembank.dto.*;
import cn.com.open.itembank.entity.*;
import cn.com.open.itembank.mapper.PaperReadMapper;
import cn.com.open.itembank.mapper.PaperWriteMapper;
import cn.com.open.itembank.service.*;
import cn.com.open.itembank.utils.DateUtil;
import cn.com.open.itembank.utils.DoubleUtil;
import cn.com.open.itembank.utils.StringUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * Created by lucky on 2017/10/30.
 */
@Service
public class PaperServiceImpl implements PaperService {

    private static String itembankIdNotExist = "题库不存在";
    private static String questionIdNotExist = "试题不存在";
    private static String idMismatches = "id不匹配";
    private static String noPermission = "无权限";
    private static String incompleteData = "参数不完整";
    private static String scoreString = "score";
    private static String xmlString = "xml";
    private static String idsString = "ids";
    private static String sectionIdString = "sectionId";
    private static String sectionTitleString = "sectionTitle";
    private static String isShufString = "isShuf";
    private static String itemTypeString = "itemType";
    private static String questionIdString = "questionId";
    private static String paperNameEmply = "试卷名称不能为空";
    private static String paperQuestionCourseNotCompare = "试题试卷不匹配";

    @Autowired
    private PaperReadMapper readMapper;
    @Autowired
    private PaperWriteMapper writeMapper;
    @Autowired
    private ItemBankRemoteService itemBankService;
    @Autowired
    private ItemRemoteService itemRemoteService;
    @Autowired
    private QtiRemoteService qtiRemoteService;
    @Autowired
    private QuestionTypeRemoteService questionTypeService;
    @Autowired
    private GenerateCreateTestPaper generateCreateTestPaperUtil;

    //region 查询相关

    //region 获取试卷

    /**
     * 获得指定题库下指定试卷的试卷模型.
     *
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param answerType 获取答案类型：0，全部；1，试题；2，答案
     * @param makeJson   是否用来获取试卷json（忽略type）
     * @return 试题模型 return model
     */
    @Override
    public ReturnModel getTestPaper(String itemBankId, String id, AnswerType answerType, boolean makeJson) {
        ReturnModel model = checkTestPaper(itemBankId, id);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        TestPaper testPaper = (TestPaper) model.getData();
        TestPaperContent content = readMapper.getQuestionTestPaperContent(id);

        TestPaperModel paperModel = makeModelForTestPaper(testPaper, content, answerType, makeJson);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(paperModel);

        return model;
    }

    /**
     * 获得输出试题模型对象.
     *
     * @param testPaper  试卷基本信息模型
     * @param content    试卷内容模型
     * @param answerType 获取答案类型：0，全部；1，试题；2，答案
     * @param makeJson   是否用来获取试卷json（忽略type）
     * @return the test paper model
     */
    private TestPaperModel makeModelForTestPaper(TestPaper testPaper, TestPaperContent content, AnswerType answerType, boolean makeJson) {

        TestPaperModel resultModel = new TestPaperModel();
        TestPaperModel qtiModel = qtiRemoteService.get(content.getContentXml());

        if (qtiModel == null) {
            return null;
        }

        //设置试卷基本信息部分
        PaperModel paperModel = qtiModel.getModel();
        paperModel.setP1(testPaper.getTestPaperID());
        paperModel.setP2(testPaper.getTestPaperName());
        paperModel.setP3(testPaper.getCourseID());
        paperModel.setP4(testPaper.getOrganizationID());
        paperModel.setP5(Double.valueOf(testPaper.getScore()));
        resultModel.setModel(paperModel);

        //设置part部分
        resultModel.getParts().addAll(qtiModel.getParts());

        //设置试题部分
        List<Object> items = new ArrayList<>();
        for (PaperPart paperPart : qtiModel.getParts()) {
            for (PaperSection paperSection : paperPart.getSections()) {
                for (PaperItem paperItem : paperSection.getItems()) {
                    String itemId = paperItem.getItemId();
                    double itemScore = paperItem.getScore();

                    //获取试卷qti
                    QuestionModel question = itemRemoteService.getItemForPaper(testPaper.getCourseID(), itemId, answerType == AnswerType.NOANSWER ? false : true);

                    if (question == null) {
                        continue;
                    }

                    Map<String, Object> jsons = new HashedMap();
                    if (makeJson) {
                        //如果仅仅用于获取保存入库的json时候，仅获取不含有子试题的试题id和分值即可，子试题分值处理交由判分服务处理
                        jsons.put("I1", itemId);
                        jsons.put("I9", itemScore);
                        items.add(jsons);
                    } else {
                        //非判分用
                        if (answerType == AnswerType.ANSWER) {
                            //仅获取答案，由于试题接口已经处理返回i1,i7,i10数据，则直接返回即可
                            Map<String, Object> map = new HashedMap();

                            switch (ItemType.fromValue(question.getI3())) {
                                case CLOZE:
                                case COMPOSITE:
                                case READINGCOMPREHENSION:
                                    List<Map<String, Object>> sub = new ArrayList<>();
                                    if (question.getSub() != null) {
                                        for (QuestionModel subItem : question.getSub()) {
                                            Map<String, Object> subMap = new HashedMap();
                                            subMap.put("I1", subItem.getI1());
                                            subMap.put("I7", subItem.getI7());
                                            subMap.put("I10", subItem.getI10());
                                            sub.add(subMap);
                                        }
                                    }
                                    map.put("I1", question.getI1());
                                    map.put("I10", question.getI10());
                                    map.put("Sub", sub);
                                    break;
                                default:
                                    map.put("I1", question.getI1());
                                    map.put("I7", question.getI7());
                                    map.put("I10", question.getI10());
                                    break;
                            }

                            items.add(map);
                        } else {
                            //获取全部或者不含答案的模型
                            //region 子题分数：e.g.试题为10分三道小题，则它们的分数为：3、3、4
                            if (itemScore > 0 && question.getSub() != null && !question.getSub().isEmpty()) {
                                int subCount = question.getSub().size();
                                for (int i = 0; i < subCount; i++) {
                                    // 是否为最后一道子题
                                    if (i == subCount - 1) {
                                        double score = (int) itemScore % subCount == 0
                                                ? DoubleUtil.round(itemScore / subCount, 4)
                                                : DoubleUtil.round(itemScore / subCount, 4) + DoubleUtil.round(itemScore % subCount, 4);

                                        question.getSub().get(i).setI9(score);
                                    } else {
                                        question.getSub().get(i).setI9(DoubleUtil.round(itemScore / subCount, 4));
                                    }
                                }
                            }

                            items.add(question);
                        }
                    }
                }
            }
        }

        resultModel.getItems().addAll(items);

        return resultModel;
    }
    //endregion

    //region获取所有试卷列表

    /**
     * 获取所有试卷列表.
     *
     * @param testPaperSearchDto the test paper dto
     * @return the paper list
     */
    @Override
    public ReturnModel getPaperList(String itemBankId, TestPaperSearchDto testPaperSearchDto) {
        ReturnModel model = new ReturnModel();
        testPaperSearchDto.setItemBankId(itemBankId);
        //题库合法性
        CourseItemBank itemBank = itemBankService.getCourseItemBankInfo(testPaperSearchDto.getItemBankId());
        if (itemBank == null) {
            model.setCode(GlobalConst.ID_NOT_EXIST);
            model.setMessage(itembankIdNotExist);
            return model;
        }
        //获取所有试卷列表
        List<TestPaper> paperList = readMapper.getPaperList(testPaperSearchDto);
        int count = readMapper.getCount(testPaperSearchDto);
        //转成json返回
        JSONObject json = new JSONObject();
        json.put("rows", paperList);
        json.put("count",count);
        model.setData(json);
        model.setCode(GlobalConst.SUCCESS);
        return model;
    }
    //endregion

    //endregion

    //region 更新相关

    //region切换试卷状态

    /**
     * 切换试卷状态
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param id         试卷id
     * @return the return model
     */
    @Override
    public ReturnModel updateStatus(String itemBankId, String id, String appKey) {
        ReturnModel model = basicCheck(itemBankId, id, appKey);
        //题库合法性
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }
        //获取试卷信息
        TestPaper testPaper = (TestPaper) model.getData();

        if (testPaper.getState() == SysState.DELETE.getIndex()) {
            model.setCode(GlobalConst.NO_PERMISSION);
            model.setMessage("无权操作该试卷");
            return model;
        }

        //给状态赋值
        int newState = (testPaper.getState() == SysState.STOP.getIndex()) ? SysState.START.getIndex() : SysState.STOP.getIndex();
        //修改状态
        writeMapper.updateStatus(id, newState);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }

    //endregion

    //region 试卷名称更改

    /**
     * 试卷名称更改
     *
     * @param appKey        appKey
     * @param itemBankId    题库id
     * @param id            试卷id
     * @param testPaperName 试卷名称
     * @return the return model
     */
    @Override
    public ReturnModel updateTestPaperName(String itemBankId, String id, String testPaperName, String appKey) {

        ReturnModel model = basicCheck(itemBankId, id, appKey);
        //题库合法性
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }
        //判断试卷名称是否为空
        if (StringUtils.isEmpty(testPaperName)) {
            model.setCode(GlobalConst.PAPER_NAME_EMPTY);
            model.setMessage(paperNameEmply);
            return model;
        }
        //获取xml信息
        TestPaperContent content = readMapper.getTestPaperContent(id);
        //修改试卷名称
        writeMapper.updateTestPaperName(id, testPaperName);
        //获取qti
        Map<String, Object> getQtiXml = qtiRemoteService.getEditTitleXml(content.getContentXml(), testPaperName);
        //修改试卷保存
        updateTestPaperContent(getQtiXml.get(xmlString).toString(), getQtiXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }

    //endregion

    //region 发布试卷

    /**
     * 发布试卷.
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param publisher  发布人
     * @return the return model
     */
    @Override
    public ReturnModel testPaperRelease(String itemBankId, String id, String publisher, String appKey) {
        ReturnModel model = basicCheck(itemBankId, id, appKey);
        //题库合法性
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }
        //获取试卷信息
        TestPaper testPaper = (TestPaper) model.getData();

        //判断试卷是否已经发布
        if (testPaper.getIsPublish() == SysState.STOP.getIndex()) {
            model.setCode(GlobalConst.SUCCESS);
            return model;
        }
        //没有发布将它改为发布并更改发布人发布时间
        writeMapper.updateIsPublish(SysState.STOP.getIndex(), publisher, DateUtil.toShowString(new Date()), id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }

    //endregion

    //region 取消试卷发布

    /**
     * 取消试卷发布.
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param id         试卷id
     * @return the return model
     */
    @Override
    public ReturnModel cancelTestPaperRelease(String itemBankId, String id, String appKey) {
        ReturnModel model = basicCheck(itemBankId, id, appKey);
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }
        TestPaper testPaper = (TestPaper) model.getData();
        //判断试卷是否已经取消发布
        if (testPaper.getIsPublish() == SysState.START.getIndex()) {
            model.setCode(GlobalConst.SUCCESS);
            return model;
        }
        //已经发布将它改为未发布并更改发布人发布时间
        int success = writeMapper.updateStopPublisher(SysState.START.getIndex(), null, null, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(success);
        return model;
    }

    //endregion

    //endregion

    //region 新增相关

    //region 试卷主体新增

    /**
     * 试卷主体新增
     *
     * @param appKey        appKey
     * @param paperModel 试卷输入输出模型
     * @return returnModel
     */
    @Override
    public ReturnModel addPaper(String itemBankId, PaperModel paperModel, String appKey) {
        ReturnModel model = new ReturnModel();

        if (paperModel == null || StringUtils.isEmpty(paperModel.getP2())) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        //校验权限
        model = checkPermission(paperModel.getP3(), appKey);
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }
        CourseItemBank itemBank = (CourseItemBank) model.getData();
        String paperId = UUID.randomUUID().toString();

        if (StringUtil.isEmpty(paperModel.getP4())) {
            paperModel.setP4("00000000-0000-0000-0000-000000000000");
        }

        TestPaper testPaper = generateCreateTestPaperUtil.getInsertPaper(paperId, paperModel.getP3(), paperModel.getP6(), paperModel.getP2(),
                paperModel.getP4(), itemBank);
        Map<String, Object> getQtiXmlMap = qtiRemoteService.getNewPaperXml(paperModel);

        generateCreateTestPaperUtil.saveInsertTestPaper(getQtiXmlMap.get(xmlString).toString(), testPaper);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(paperId);
        return model;
    }


    //region 新增私有方法


    /**
     * 校验权限.
     *
     * @param itemBankId 题库id
     * @param appKey     appKey
     * @return the return model
     */
    private ReturnModel checkPermission(String itemBankId, String appKey) {
        ReturnModel model = new ReturnModel();

        CourseItemBank itemBank = itemBankService.getCourseItemBankInfo(itemBankId);
        if (itemBank == null) {
            model.setCode(GlobalConst.ID_NOT_EXIST);
            model.setMessage(itembankIdNotExist);
            return model;
        }

        //确认除非非限定appid否则只能修改appid对应的itemBankId下的试题
        if (!itemBankService.hasPermission(itemBankId, appKey)) {
            model.setCode(GlobalConst.NO_PERMISSION);
            model.setMessage(noPermission);
            return model;
        }

        model.setData(itemBank);
        model.setCode(GlobalConst.SUCCESS);
        return model;
    }
    //endregion

    //endregion

    //region 复制试卷

    //region 题库内复制试卷

    /**
     * 题库内复制试卷.
     *
     * @param itemBankId the 题库id
     * @param oldId      the 旧试卷id
     * @param newId      the 新试卷id
     * @param appKey     the app key
     * @return the return model
     */
    @Override
    public ReturnModel copyTestPaper(String itemBankId, String oldId, String newId, String appKey) {

        ReturnModel model = basicCheck(itemBankId, oldId, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        TestPaper testPaper = (TestPaper) model.getData();
        //查询试卷是否存在，存在则返回
        TestPaper newPaper = readMapper.getQuestionTestPaper(itemBankId, newId);
        if (newPaper != null) {
            model.setCode(GlobalConst.PAPER_EXIST);
            model.setMessage("试卷ID已存在");
            return model;
        }

        copy(oldId, newId, testPaper);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(newId);
        return model;
    }
    //endregion

    //region 试卷复制

    /**
     * 试卷复制.
     *
     * @param oldId     the 旧试卷id
     * @param newId     the 新试卷id
     * @param testPaper the 试卷模型
     */
    private void copy(String oldId, String newId, TestPaper testPaper) {
        //将旧试卷的id变更成为新id
        testPaper.setTestPaperID(newId);
        //记录拷贝标记
        testPaper.setComment(String.format("copy from %s", oldId));
        //获取旧的试卷xml
        TestPaperContent content = readMapper.getTestPaperContent(oldId);

        // 根据旧的试卷xml和新的试卷id获取新试卷的xml
        Map<String, Object> getCopyTestPaperXml = qtiRemoteService.getCopyTestPaperXml(content.getContentXml(), newId);
        //新增试卷保存
        generateCreateTestPaperUtil.saveInsertTestPaper(getCopyTestPaperXml.get(xmlString).toString(), testPaper);

        //查询曝光表信息
        List<QuestionDisplayInfo> qIdList = readMapper.getQuestionDisplayInfo(oldId);

        //更新试题曝光信息
        for (QuestionDisplayInfo questionIdList : qIdList) {
            generateCreateTestPaperUtil.updateQuestionDisplay(newId, questionIdList.getQuestionID(), true, DateUtil.getCurrentTimeToShowString());
        }
    }
    //endregion

    //region 跨题库批量复制试卷

    /**
     * 跨题库批量复制试卷.
     *
     * @param sourceItembankId 原题库id
     * @param targetItemBankId 目标题库id
     * @param targetOrgId      目标题库机构id
     * @param testPaperMap     旧新试题id的map
     * @return the map         返回类型
     */
    @Override
    public Map<String, String> copyCrossItemBank(String sourceItembankId, String targetItemBankId, String targetOrgId, Map<String, String> testPaperMap) {
        Map<String, String> returnMap = new HashedMap();

        if (testPaperMap == null || testPaperMap.isEmpty()) {
            return returnMap;
        }

        String s = StringUtil.formatSqlInString(String.join(",", testPaperMap.keySet()));
        //获取旧的试卷信息
        List<TestPaper> sourcePapers = readMapper.getPapersForCopy(sourceItembankId, s);

        if (sourcePapers.isEmpty()) {
            return returnMap;
        }

        //遍历每个试卷
        for (TestPaper paper : sourcePapers) {
            String sourcePaperId = paper.getTestPaperID();
            //生成新的试卷id
            String targetPaperId = UUID.randomUUID().toString();
            //更新试卷相关信息
            paper.setCourseID(targetItemBankId);
            paper.setOrganizationID(targetOrgId);
            //复制试卷
            copy(paper.getTestPaperID(), targetPaperId, paper);
            //将试卷id更新
            returnMap.put(sourcePaperId, targetPaperId);
        }

        return returnMap;
    }

    //endregion

    //endregion

    //region 试卷导入

    /**
     * 试卷导入.
     *
     * @param importParameter 导入模型
     * @return the return model
     */
    @Override
    public ReturnModel importPaper(ImportParameter importParameter) {
        ReturnModel returnModel = new ReturnModel();

        //判断是否存在试卷
        boolean isExistPaper = false;

        //检查paperId
        if (!StringUtils.isEmpty(importParameter.getPaperId())) {
            ReturnModel model = checkTestPaper(importParameter.getItemBankId(), importParameter.getPaperId());

            isExistPaper = (model.getCode() == GlobalConst.SUCCESS);
        }

        //调用试题的导入服务
        ReturnModelForTestPaper itemReturn = itemRemoteService.importLogic(importParameter);

        if (itemReturn.getCode() != GlobalConst.SUCCESS) {
            returnModel.setCode(itemReturn.getCode());
            returnModel.setMessage(itemReturn.getMessage());
            return returnModel;
        }

        //获得到返回值中的试卷模型
        TestPaperModel testPaperModel = itemReturn.getData();
        Map<String, Object> getEditQuestionXml;

        String newPid = importParameter.getPaperId();
        if (!isExistPaper) {
            //新增试卷
            //得到试卷id
            newPid = UUID.randomUUID().toString();
            PaperModel paperModel = new PaperModel();
            paperModel.setP1(newPid);
            paperModel.setP2(importParameter.getPaperTitle());

            testPaperModel.setModel(paperModel);
            //得到新试卷xml
            getEditQuestionXml = qtiRemoteService.getFullPaperXml(testPaperModel);
            //得到题库信息
            CourseItemBank itemBank = itemBankService.getCourseItemBankInfo(importParameter.getItemBankId());
            //得到试卷主体信息
            TestPaper testPaper = generateCreateTestPaperUtil.getInsertPaper(newPid, importParameter.getItemBankId(), importParameter.getUserId(),
                    importParameter.getPaperTitle(), importParameter.getOrganizationId(), itemBank);
            //保存新增试卷
            generateCreateTestPaperUtil.saveInsertTestPaper(getEditQuestionXml.get(xmlString).toString(), testPaper);
            //更新试题曝光
            increaseQuestionDisplayForNewPaper(newPid, testPaperModel, DateUtil.toShowString(new Date()));

        } else {
            //存在试卷
            //得到原始试卷内容
            TestPaperContent content = readMapper.getTestPaperContent(importParameter.getPaperId());
            //构建与qti服务通信的模型
            TestPaperForFullEdit model = new TestPaperForFullEdit();
            model.setOrginalXml(content.getContentXml());
            model.setPaper(testPaperModel);
            //获得更新后试卷的xml
            getEditQuestionXml = qtiRemoteService.getFullPaperXmlWithExistXml(model);
            //保存更新后的试卷
            updateTestPaperContent(getEditQuestionXml.get(xmlString).toString(), getEditQuestionXml.get(scoreString).toString(),
                    importParameter.getItemBankId(), importParameter.getPaperId());

            List<String> idslist = (List) getEditQuestionXml.get(idsString);
            //更新试题曝光
            increaseQuestionDisplayForExistPaper(importParameter.getPaperId(), idslist, DateUtil.toShowString(new Date()));
        }

        returnModel.setCode(GlobalConst.SUCCESS);
        returnModel.setData(newPid);
        return returnModel;
    }

    /**
     * 给已经存在的试卷增加给定试题列表的曝光次数.
     *
     * @param id      试卷Id
     * @param idslist 试题列表
     * @param newDate 曝光时间
     */
    private void increaseQuestionDisplayForExistPaper(String id, List<String> idslist, String newDate) {

        if (!idslist.isEmpty()) {
            for (String questionId : idslist) {
                generateCreateTestPaperUtil.updateQuestionDisplay(id, questionId, true, newDate);
            }
        }
    }

    /**
     * 给新增试卷增加试题曝光次数.
     *
     * @param id         试卷Id
     * @param paperModel 试卷模型
     * @param newDate    曝光时间
     */
    private void increaseQuestionDisplayForNewPaper(String id, TestPaperModel paperModel, String newDate) {

        for (PaperPart part : paperModel.getParts()) {
            for (PaperSection section : part.getSections()) {
                for (PaperItem item : section.getItems()) {
                    generateCreateTestPaperUtil.updateQuestionDisplay(id, item.getItemId(), true, newDate);
                }
            }
        }
    }
    //endregion

    //endregion

    //region 删除相关

    //region 试卷删除(默认删除是自动取消发布后删除)

    /**
     * 试卷删除(默认删除是自动取消发布后删除)
     *
     * @param itemBankId   题库ID
     * @param id           试卷id
     * @param isAutoDelete 是否自动删除： true 表示会自动取消发布后删除
     * @param appKey       所属AppKey
     * @return
     */
    @Override
    public ReturnModel deleteAuto(String itemBankId, String id, boolean isAutoDelete, String appKey) {
        ReturnModel model = basicCheck(itemBankId, id, appKey);
        //题库合法性
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }
        //获取试卷信息
        TestPaper testPaper = (TestPaper) model.getData();
        //如果isAutoDelete为true
        if (isAutoDelete) {
            ReturnModel cancelTestPaperReleaseModel = cancelTestPaperRelease(itemBankId, id, appKey);
            cancelTestPaperReleaseModel.getData();
        } else {
            if (testPaper.getIsPublish() == YesOrNo.YES.getIndex()) {
                model.setCode(GlobalConst.DATA_EXIST);
                model.setMessage("其他数据已存在");
                return model;
            }
        }
        writeMapper.deletePaperDisplay(id);
        writeMapper.updateStatus(id, SysState.DELETE.getIndex());

        model.setCode(GlobalConst.SUCCESS);
        return model;
    }

    //endregion

    //endregion

    //region私有方法

    /**
     * 根据appKey，题库id和试卷id检测试卷状态，所有权.
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param id         试卷id
     * @return the return model
     */
    private ReturnModel basicCheck(String itemBankId, String id, String appKey) {
        //基础检查(id是否存在，合法；有无权限操作；题库是否存在)
        ReturnModel model = checkTestPaper(itemBankId, id);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        //确认除非非限定appid否则只能修改appid对应的itemBankId下的试卷
        if (!itemBankService.hasPermission(itemBankId, appKey)) {
            model.setCode(GlobalConst.NO_PERMISSION);
            model.setMessage(noPermission);
            return model;
        }

        model.setCode(GlobalConst.SUCCESS);
        return model;
    }

    /**
     * 根据题库id和试卷id检测题库，试卷，以及题库试卷关系.
     *
     * @param itemBankId 题库id
     * @param id         试卷id
     * @return the return model
     */
    private ReturnModel checkTestPaper(String itemBankId, String id) {
        ReturnModel model = new ReturnModel();

        //id合法性
        if (StringUtils.isEmpty(itemBankId) || StringUtils.isEmpty(id)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        //题库合法性
        CourseItemBank itemBank = itemBankService.getCourseItemBankInfo(itemBankId);
        if (itemBank == null) {
            model.setCode(GlobalConst.COURSE_NOT_EXIST);
            model.setMessage(itembankIdNotExist);
            return model;
        }

        //题库和试卷匹配
        TestPaper testPaper = readMapper.getQuestionTestPaper(itemBankId, id);
        if (testPaper == null) {
            model.setCode(GlobalConst.QUESTION_ITEM_BANK_NOT_MATCH);
            model.setData(null);
            model.setMessage(idMismatches);
            return model;
        }

        model.setData(testPaper);
        model.setCode(GlobalConst.SUCCESS);
        return model;
    }

    //endregion

    //region 大题相关

    //region 大题自身删除

    /**
     * 大题自身删除
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param index      大题序号
     * @return
     */
    @Override
    public ReturnModel removeSection(String itemBankId, String id, String index, String appKey) {
        //基础检测
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);

        // 获取qti
        Map<String, Object> getRemoveSectionXml = qtiRemoteService.getRemoveSectionXml(content.getContentXml(), index);

        //获取当前时间
        List<String> idslist = (List) getRemoveSectionXml.get(idsString);
        if (!idslist.isEmpty()) {
            for (String questionId : idslist) {
                generateCreateTestPaperUtil.updateQuestionDisplay(id, questionId, false, null);
            }
        }
        //修改试卷保存
        updateTestPaperContent(getRemoveSectionXml.get(xmlString).toString(), getRemoveSectionXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        return model;
    }

    //endregion

    //region 大题所含试题删除

    /**
     * 大题所含试题删除
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param index      大题序号
     * @return
     */
    @Override
    public ReturnModel removeSectionQuestion(String itemBankId, String id, String index, String questionId, String appKey) {
        //基础检测
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index) || StringUtils.isEmpty(questionId)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);

        return qtiXml(content.getContentXml(), itemBankId, id, questionId);
    }

    //endregion

    //region 大题批量试题删除

    /**
     * 大题批量试题删除
     *
     * @param appKey     appKey
     * @param itemBankId 题库id
     * @param questionIdList 试卷id集合
     * @return
     */
    @Override
    public ReturnModel removeSectionQuestionList(String itemBankId, String id, List<String> questionIdList, String appKey) {
        //基础检测
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (questionIdList.isEmpty()) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);

        for (String questionId : questionIdList) {
            // 获取qti
            model = qtiXml(content.getContentXml(), itemBankId, id, questionId);
        }
        model.setCode(GlobalConst.SUCCESS);
        return model;
    }

    //endregion

    //region 大题内容修改

    /**
     * 大题内容修改
     *
     * @param itemBankId   题库id
     * @param id           试卷id
     * @param sectionTitle 大题名称
     * @param index        大题序号
     * @param shuf         是否乱序
     * @param appKey       appKey
     * @return
     */
    @Override
    public ReturnModel updateSectionContent(String itemBankId, String id, String index, String sectionTitle, boolean shuf, String appKey) {
        //基础检测
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index) || StringUtils.isEmpty(sectionTitle)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);
        Map<String, Object> map = new HashMap<>();
        map.put(xmlString, content.getContentXml());
        map.put(sectionIdString, index);
        map.put(sectionTitleString, sectionTitle);
        map.put(isShufString, shuf);
        // 获取qti
        Map<String, Object> updateSectionContent = qtiRemoteService.getEditSectionXml(map);
        updateTestPaperContent(updateSectionContent.get(xmlString).toString(), updateSectionContent.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }

    //endregion

    //region 大题试题分值修改

    /**
     * 大题试题分值修改
     *
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param index      大题序号
     * @param questionId 试题id
     * @param score      试题分值
     * @param appKey     appKey
     * @return
     */
    @Override
    public ReturnModel updateSectionQuestionScore(String itemBankId, String id, String index, String questionId, double score, String appKey) {
        //基础检测
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index) || StringUtils.isEmpty(questionId) || score <= 0) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);
        // 获取qti
        Map<String, Object> getEditSectionScoreXml = qtiRemoteService.getEditSectionScoreXml(content.getContentXml(), index, questionId, score);
        updateTestPaperContent(getEditSectionScoreXml.get(xmlString).toString(), getEditSectionScoreXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }
    //endregion

    // region 大题所有试题分值修改

    /**
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param index      大题序号
     * @param score      试题分值
     * @param appKey     appKey
     * @return
     */
    @Override
    public ReturnModel updateSectionScore(String itemBankId, String id, String index, double score, String appKey) {
        //基础检测
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index) || score <= 0) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);
        String questionId = "";
        // 获取qti
        Map<String, Object> getEditSectionScoreXml = qtiRemoteService.getEditSectionScoreXml(content.getContentXml(), index, questionId, score);
        updateTestPaperContent(getEditSectionScoreXml.get(xmlString).toString(), getEditSectionScoreXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }

    //endregion

    //region 大题顺序调整

    /**
     * 大题顺序调整
     *
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param index      大题序号
     * @param m          上移/下移
     * @param appKey     appKey
     * @return
     */
    @Override
    public ReturnModel updateSectionOrder(String itemBankId, String id, String index, boolean m, String appKey) {
        //基础验证
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);
        // 获取qti
        Map<String, Object> getEditSectionScoreXml = qtiRemoteService.getMoveSectionXml(content.getContentXml(), index, m);
        //修改试卷保存
        updateTestPaperContent(getEditSectionScoreXml.get(xmlString).toString(), getEditSectionScoreXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }


    //endregion

    //region 大题试题顺序调整

    /**
     * 大题试题顺序调整
     *
     * @param itemBankId 题库id
     * @param id         试卷id
     * @param index      大题序号
     * @param questionId 试题id
     * @param m          上移/下移
     * @param appKey     appKey
     * @return
     */
    @Override
    public ReturnModel updateSectionQuestionOrder(String itemBankId, String id, String index, String questionId, boolean m, String appKey) {
        //基础验证
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(index) || StringUtils.isEmpty(questionId)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);
        // 获取qti
        Map<String, Object> getEditSectionScoreXml = qtiRemoteService.getMoveQuestionXml(content.getContentXml(), index, questionId, m);
        //修改试卷保存
        updateTestPaperContent(getEditSectionScoreXml.get(xmlString).toString(), getEditSectionScoreXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        model.setData(null);
        return model;
    }
    //endregion

    //region 大题试题关联新增

    /**
     * @param itemBankId 题库id
     * @param paperId    试卷id
     * @param questionId 试题id
     * @param shuf       是否乱序
     * @param score      分数
     * @param appKey     appkey
     * @return
     */
    @Override
    public ReturnModel addSectionQuestion(String itemBankId, String paperId, String questionId, boolean shuf, double score, String appKey) {
        ReturnModel model = basicCheck(itemBankId, paperId, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (StringUtils.isEmpty(questionId) || score <= 0) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        //获取试题信息
        Question question = itemRemoteService.getItem(questionId);
        if (question == null || question.getStatus() != SysState.START.getIndex()) {
            model.setCode(GlobalConst.QUESTION_NOT_EXIST);
            model.setMessage(questionIdNotExist);
            return model;
        }

        //根据试卷id获取试卷content
        TestPaperContent content = readMapper.getTestPaperContent(paperId);

        //验证试题和题库是否匹配
        model = checkItemBankQuestionRelation(itemBankId, paperId, question, content, shuf, score);

        //返回
        return model;
    }
    //endregion

    //region 验证试题和题库是否匹配

    /**
     * @param itemBankId 题库id
     * @param paperId    试卷id
     * @param question   试题模型
     * @param shuf       是否乱序
     * @param score      分数
     * @return
     */
    private ReturnModel checkItemBankQuestionRelation(String itemBankId, String paperId, Question question, TestPaperContent content, boolean shuf, double score) {
        ReturnModel returnModel = new ReturnModel();
        //试题和题库是否匹配
        boolean flag = itemRemoteService.checkItemBankQuestionRelation(itemBankId, question.getQuestionId());

        if (!flag) {
            returnModel.setCode(GlobalConst.PAPER_QUESTION_COURSE_NOT_COMPARE);
            returnModel.setMessage(paperQuestionCourseNotCompare);
            return returnModel;
        }

        //获取试题类别
        QuestionType questionType = questionTypeService.getQuestionType(question.getQuestionTypeId());

        Map<String, Object> map = new HashMap<>();
        map.put(xmlString, content.getContentXml());
        map.put(sectionIdString, questionType.getSectionID());
        map.put(sectionTitleString, questionType.getQuestionTypeName());
        map.put(isShufString, shuf);
        map.put("questionId", question.getQuestionId());
        map.put(scoreString, score);
        map.put("itemType", ItemType.fromValue(questionType.getQuestionInnerTypeID()));

        Map<String, Object> getQtiXmlMap = qtiRemoteService.getAddQuestionXml(map);

        updateTestPaperContent(getQtiXmlMap.get(xmlString).toString(), getQtiXmlMap.get(scoreString).toString(), itemBankId, paperId);
        generateCreateTestPaperUtil.updateQuestionDisplay(paperId, question.getQuestionId(), true, DateUtil.toShowString(new Date()));

        returnModel.setCode(GlobalConst.SUCCESS);
        returnModel.setData(null);
        return returnModel;

    }

    //endregion

    //region 大题试题关联批量新增

    /**
     * 大题试题关联批量新增
     *
     * @param itemBankId     题库id
     * @param id             试卷id
     * @param questionIdList 试题id集合
     * @param score          分数
     * @param appKey         appkey
     * @return
     */
    @Override
    public ReturnModel addExistQuestionList(String itemBankId, String id, List<String> questionIdList, double score, String appKey) {
        ReturnModel model = basicCheck(itemBankId, id, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        if (questionIdList.isEmpty()) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        TestPaperContent content = readMapper.getTestPaperContent(id);

        for (String questionId : questionIdList) {
            //试题和题库是否匹配
            boolean flag = itemRemoteService.checkItemBankQuestionRelation(itemBankId, questionId);

            if (!flag) {
                model.setCode(GlobalConst.PAPER_QUESTION_COURSE_NOT_COMPARE);
                model.setMessage(paperQuestionCourseNotCompare);
                return model;
            }

            //获取试题信息
            Question question = itemRemoteService.getItem(questionId);
            //获取试题类别
            QuestionType questionType = questionTypeService.getQuestionType(question.getQuestionTypeId());

            Map<String, Object> map = new HashMap<>();
            map.put(xmlString, content.getContentXml());
            map.put(sectionIdString, questionType.getSectionID());
            map.put(sectionTitleString, questionType.getQuestionTypeName());
            map.put(isShufString, true);
            map.put(questionIdString, questionId);
            map.put(scoreString, score);
            map.put(itemTypeString, ItemType.fromValue(questionType.getQuestionInnerTypeID()));

            Map<String, Object> getQtiXmlMap = qtiRemoteService.getAddQuestionXml(map);

            updateTestPaperContent(getQtiXmlMap.get(xmlString).toString(), getQtiXmlMap.get(scoreString).toString(), itemBankId, id);
            generateCreateTestPaperUtil.updateQuestionDisplay(id, questionId, true, DateUtil.toShowString(new Date()));

            model.setCode(GlobalConst.SUCCESS);
        }
        model.setData(null);
        return model;
    }

    //endregion

    //region 大题试题修改

    /**
     * 大题试题修改
     *
     * @param itemBankId    题库ID
     * @param paperId       试卷ID
     * @param index         大题序号
     * @param questionId    试题id
     * @param copy          是否复制
     * @param questionModel 试题模型
     * @param appKey        所属AppKey
     * @return
     */
    @Override
    public ReturnModel updateSectionQuestion(String itemBankId, String paperId, String index, String questionId, Boolean copy,
                                             QuestionModel questionModel, String appKey) {
        String newPaperId = paperId;
        ReturnModel model = basicCheck(itemBankId, paperId, appKey);
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        //参数是否完整
        if (StringUtils.isEmpty(index) || StringUtils.isEmpty(questionId)) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage(incompleteData);
            return model;
        }

        //获取当前时间
        Date newDate = new Date();

        //如果复制试卷
        if (copy) {
            //新的试卷id
            newPaperId = UUID.randomUUID().toString().toUpperCase();
            model = copyTestPaper(itemBankId, paperId, newPaperId, appKey);
            if (model.getCode() != GlobalConst.SUCCESS) {
                return model;
            }
        }

        //修改试题
        ReturnModel newQuestionModel = itemRemoteService.updateQuestion(itemBankId, questionId, questionModel, appKey);
        String newQuestionId = (String) newQuestionModel.getData();
        if (StringUtil.isEmpty(newQuestionId)) {
            model.setCode(GlobalConst.DATA_BASE_ERROR);
            model.setMessage("数据操作失败");
            return model;
        }

        //获取试卷内容表
        TestPaperContent content = readMapper.getTestPaperContent(newPaperId);
        Map<String, Object> map = new HashMap<>();
        map.put(xmlString, content.getContentXml());
        map.put(sectionIdString, index);
        map.put(questionIdString, questionId);
        map.put("newQuestionId", newQuestionId);
        map.put(scoreString, questionModel.getI9());
        map.put(itemTypeString, ItemType.fromValue(questionModel.getI3()));

        // 获取qti
        Map<String, Object> getEditQuestionXml = qtiRemoteService.getEditQuestionXml(map);

        //保存json
        updateTestPaperContent(getEditQuestionXml.get(xmlString).toString(), getEditQuestionXml.get(scoreString).toString(), itemBankId, paperId);

        if (!questionId.equalsIgnoreCase(newQuestionId)) {
            //新试题曝光次数为1
            generateCreateTestPaperUtil.updateQuestionDisplay(newPaperId, questionId, true, DateUtil.toShowString(newDate));
            //原试题曝光次数减1
            generateCreateTestPaperUtil.updateQuestionDisplay(newPaperId, questionId, false, DateUtil.toShowString(newDate));
        }

        model.setCode(GlobalConst.SUCCESS);
        model.setData(newPaperId);
        return model;
    }

    //endregion

    //region 大题试题新增

    /**
     * 大题试题新增
     *
     * @param itemBankId    题库id
     * @param paperId       试卷id
     * @param questionModel 试题模型
     * @param shuf          是否乱序
     * @param score         分数
     * @param appKey        appkey
     * @return
     */
    @Override
    public ReturnModel addSectionQuestioninsert(String itemBankId, String paperId, QuestionModel questionModel, boolean shuf, double score, String appKey) {
        ReturnModel model = basicCheck(itemBankId, paperId, appKey);

        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        ReturnModel newQuestionModel = itemRemoteService.addQuestion(itemBankId, questionModel, appKey, Source.OUTER.getIndex());
        if (newQuestionModel.getCode() != GlobalConst.SUCCESS) {
            return newQuestionModel;
        }

        String questionId = (String) newQuestionModel.getData();
        //获取试题信息
        Question question = itemRemoteService.getItem(questionId);
        if (question == null || question.getStatus() != SysState.START.getIndex()) {
            model.setCode(GlobalConst.QUESTION_NOT_EXIST);
            model.setMessage(questionIdNotExist);
            return model;
        }

        //根据试卷id获取试卷content
        TestPaperContent content = readMapper.getTestPaperContent(paperId);

        //验证试题和题库是否匹配
        model = checkItemBankQuestionRelation(itemBankId, paperId, question, content, shuf, score);

        //返回
        return model;
    }

    //endregion

    //endregion

    // region 修改试卷保存

    private ReturnModel qtiXml(String xml, String itemBankId, String id, String questionId) {
        ReturnModel model = new ReturnModel();
        // 获取qti
        Map<String, Object> getRemoveQuestionXml = qtiRemoteService.getRemoveQuestionXml(xml, questionId);
        boolean isExistQuestion = (boolean) getRemoveQuestionXml.get("exist");

        if (!isExistQuestion) {
            model.setCode(GlobalConst.ID_NOT_EXIST);
            model.setMessage(questionIdNotExist);
            return model;
        }

        //修改试卷保存并且修改曝光信息
        generateCreateTestPaperUtil.updateQuestionDisplay(id, questionId, false, null);
        updateTestPaperContent(getRemoveQuestionXml.get(xmlString).toString(),
                getRemoveQuestionXml.get(scoreString).toString(), itemBankId, id);

        model.setCode(GlobalConst.SUCCESS);
        return model;
    }

    //region 修改试卷保存

    /**
     * 修改试卷保存
     *
     * @param xml
     * @param score 分数
     * @param id    试卷编号
     * @return
     */
    private int updateTestPaperContent(String xml, String score, String itemBankId, String id) {

        //更新xml
        int isSuccess = writeMapper.updateTestPaperContent(xml, id);

        //更新json
        generateCreateTestPaperUtil.updateJson(itemBankId, id);

        if (isSuccess > 0 && !score.isEmpty()) {
            isSuccess = writeMapper.updateTestPaperScore(score, id);
        }

        return isSuccess > 0 ? GlobalConst.SUCCESS : GlobalConst.DATA_BASE_ERROR;
    }
    //endregion

    //endregion


}
